﻿@using Microsoft.Extensions.Options;
@using SimpleIdServer.IdServer.Options;
@using IdServer.Resources;
@model SimpleIdServer.IdServer.Fido.UI.ViewModels.RegisterWebauthnViewModel

@inject IOptions<IdServerHostOptions> configuration

@{
    Layout = "~/Views/Shared/_RegisterLayout.cshtml";
    ViewBag.Title = AuthenticateWebauthnResource.register_title;
}

<h5>@(User.Identity.IsAuthenticated ? AuthenticateWebauthnResource.update_webauthn : AuthenticateWebauthnResource.register_webauthn)</h5>

<div id="registrationContainer">
    <ul class="list-group mb-3" id="errors">
        @foreach (var modelState in ViewData.ModelState.Values)
        {
            foreach (var error in modelState.Errors)
            {
                <li class="list-group-item list-group-item-danger">@AuthenticateWebauthnResource.ResourceManager.GetString(error.ErrorMessage)</li>
            }
        }
    </ul>

    <!-- Registration form -->
    <form id="registerWebauthn">
        <div class="form-floating mb-3">
            @if(!string.IsNullOrWhiteSpace(Model.Login))
            {
                <input asp-for="Login" placeholder="@AuthenticateWebauthnResource.login" id="floatingLogin" type="text" class="form-control" disabled="true" />
            }
            else
            {
                <input asp-for="Login" placeholder="@AuthenticateWebauthnResource.login" id="floatingLogin" type="text" class="form-control" />
            }
            <label for="floatingLogin">@AuthenticateWebauthnResource.login</label>
        </div>
        <div class="form-floating mb-3">
            <input asp-for="DisplayName" placeholder="@AuthenticateWebauthnResource.display_name" id="floatingDisplayName" type="text" class="form-control" />
            <label for="floatingDisplayName">@AuthenticateWebauthnResource.display_name</label>
        </div>
        <button type="submit" class="btn btn-primary card-link">@AuthenticateWebauthnResource.register</button>
    </form>
</div>

<div style="display: none;" id="registerSuccessMessage">
    <div class="alert alert-success">
        @AuthenticateWebauthnResource.credential_added
    </div>
    @if(!string.IsNullOrWhiteSpace(Model.RedirectUrl))
    {
        <a href="@Model.RedirectUrl" class="btn btn-primary mt-1">@LayoutResource.back</a>
    }
</div>

@section SubScripts {
    <script type="text/javascript">
        $(document).ready(function() {
            var beginRegisterUrl = "@Model.BeginRegisterUrl";
            var endRegisterUrl = "@Model.EndRegisterUrl";
            var redirectUrl = "@Model.RedirectUrl";

            var toggleBtn = function(isDisabled) {
                $("#registerWebauthn button[type='submit']").attr('disabled', isDisabled);
            }

            var displayError = function(errorJson) {
                console.error(errorJson);
                $("#errors").empty();
                $("#errors").append("<li class='list-group-item list-group-item-danger'>" + errorJson["error_description"] + "</li>");
            }

            var displaySuccessMessage = function () {
                $("#registerSuccessMessage").css('display', '');
                $("#registrationContainer").css('display', 'none');
            }

            async function registerCredential(newCredential, sessionId, login, nextRegistrationRedirectUrl) {
                let attestationObject = new Uint8Array(newCredential.response.attestationObject);
                let clientDataJSON = new Uint8Array(newCredential.response.clientDataJSON);
                let rawId = new Uint8Array(newCredential.rawId);
                const serializedAuthenticatorAttestationRawResponse = {                    
                    id: newCredential.id,
                    rawId: coerceToBase64Url(rawId),
                    type: newCredential.type,
                    extensions: newCredential.getClientExtensionResults(),
                    response: {
                        attestationObject: coerceToBase64Url(attestationObject),
                        clientDataJSON: coerceToBase64Url(clientDataJSON)
                    }
                };

                let response = await fetch(endRegisterUrl, {
                    method: 'POST',
                    body: JSON.stringify({
                        attestation: serializedAuthenticatorAttestationRawResponse,
                        login: login,
                        session_id: sessionId
                    }),
                    headers: {
                        "Accept": "application/json",
                        "Content-Type": "application/json"
                    }
                });
                let responseJson = await response.json();
                if (!response.ok) {
                    toggleBtn(false);
                    displayError(responseJson);
                    return;
                }

                if (nextRegistrationRedirectUrl) {
                    window.location.href = nextRegistrationRedirectUrl;
                    return;
                }
                
                toggleBtn(false);
                displaySuccessMessage();
            }

            async function makeCredential(login, displayName) {
                toggleBtn(true);

                let response = await fetch(beginRegisterUrl, {
                    method: 'POST',
                    body: JSON.stringify({ login: login, display_name: displayName, credential_type: 'webauthn' }),
                    headers: {
                        "Accept": "application/json",
                        "Content-Type": "application/json"
                    }
                });
                let responseJson = await response.json();
                if(!response.ok) {
                    toggleBtn(false);
                    displayError(responseJson);
                    return;
                }

                let makeCredentialOptions = responseJson["credential_create_options"];
                let sessionId = responseJson["session_id"];
                let nextRegistrationRedirectUrl = null;
                if (responseJson['next_registration_redirect_url']) {
                    nextRegistrationRedirectUrl = responseJson['next_registration_redirect_url'];
                }

                makeCredentialOptions.challenge = coerceToArrayBuffer(makeCredentialOptions.challenge);
                makeCredentialOptions.user.id = coerceToArrayBuffer(makeCredentialOptions.user.id);
                makeCredentialOptions.excludeCredentials = makeCredentialOptions.excludeCredentials.map((c) => {
                    c.id = coerceToArrayBuffer(c.id);
                    return c;
                });
                if (makeCredentialOptions.authenticatorSelection.authenticatorAttachment === null) makeCredentialOptions.authenticatorSelection.authenticatorAttachment = undefined;
                let newCredential;
                try {
                    newCredential = await navigator.credentials.create({
                        publicKey: makeCredentialOptions
                    });
                } catch (e) {
                    var msg = "Could not create credentials in browser. Probably because the username is already registered with your authenticator. Please change username or authenticator."
                    console.error(msg, e);
                    toggleBtn(false);
                    return;
                }

                await registerCredential(newCredential, sessionId, login, nextRegistrationRedirectUrl);
            };

            $("#registerWebauthn").submit(function (e) {
                e.preventDefault();
                var login = $("#registerWebauthn input[name='Login']").val();
                var displayName = $("#registerWebauthn input[name='DisplayName']").val();
                makeCredential(login, displayName);
            });
        });
    </script>
}